// *********************************************************
//      Copyright (c) Kosta Gaitanis
//      All rights reserved
//
//      k.gaitanis@gmail.com
//
// *********************************************************

#include <QtOpenGL/QtOpenGL>

#include "Face.h"


Face::Face(Face::PrimitiveType type) :
    m_color(Qt::white),
    m_type(type)
{
}

Face::~Face()
{
}

void Face::paint()
{
    /* FIXME complete the code */

    // set the color of the face using glColor()
    glColor3f(this->m_color.redF(), this->m_color.greenF(), this->m_color.blueF());

    // select the appropriate type of primitive according to m_type.
    // use glBegin(  type_of_primitive )
    switch (this->m_type) {
    case Line:
        glBegin(GL_LINE);
        break;
    case Triangles:
        glBegin(GL_TRIANGLES);
        break;
    case Quads:
        glBegin(GL_QUADS);
        break;
    case Polygon:
        glBegin(GL_POLYGON);
        break;
    case TriangleStrip:
        glBegin(GL_TRIANGLE_STRIP);
        break;
    default:
        break;
    }

    // loop through all the points of this face.
    for (int p = 0; p < this->count(); ++p) {
        // send the texture coordinates to the GPU (if any) using glTexCoord()
        if(!m_textures[p].isEmpty())
            glTexCoord3d(this->m_textures[p].x(), this->m_textures[p].y(), this->m_textures[p].z());

        // send the normal coordinates to the GPU (if any) using glNormal()
        if(!m_normals[p].isEmpty())
            glNormal3d(this->m_normals[p].x(), this->m_normals[p].y(), this->m_normals[p].z());

        // send the vertice coordinates to the GPU using glVertex()
        if(!m_coordinates[p].isEmpty())
            glVertex3dv(this->m_coordinates[p].getGLCoordinates());
    }
    glEnd();
    // don't forget to tell the GPU that this primitive is complete
    /* STOP here */
}

Face::Face(const Face &other)
{
    m_coordinates = other.m_coordinates;
    m_normals = other.m_normals;
    m_textures = other.m_textures;
    m_color = other.m_color;
    m_type = other.m_type;
}

bool Face::operator ==(const Face &other) const
{
    if (m_type != other.m_type) {
        return false;
    }

    Vector v;
    int i = 0;
    if (count() != other.count()) {
        return false;
    }
    foreach (v, m_coordinates) {
        if (v != other.m_coordinates.at(i)) {
            return false;
        }
        i++;
    }
    i = 0;
    foreach (v, m_normals) {
        if (v != other.m_normals.at(i)) {
            return false;
        }
        i++;
    }
    i = 0;
    foreach (v, m_textures) {
        if (v != other.m_textures.at(i)) {
            return false;
        }
        i++;
    }

    return (m_color == other.m_color);
}

bool Face::operator !=(const Face &other) const
{
    return (!operator ==(other));
}

Face &Face::operator =(const Face &other)
{
    m_coordinates = other.getCoordinates();
    m_normals = other.getNormals();
    m_textures = other.getTextures();
    m_color = other.getColor();
    m_type = other.m_type;

    return *this;
}

void Face::addPoint(int position, const Vector &coordinates, const Vector &normal, const Vector &texture)
{
    if ((position < 0) || (position > count())) {
        qDebug() << "Trying to add a point to non-valid position" << position;
        return;
    }
    m_coordinates.insert(position, coordinates);
    m_normals.insert(position, normal);
    m_textures.insert(position, texture);
}

void Face::addPoint(const Vector &coordinates, const Vector &normal, const Vector &texture)
{
    addPoint(count(), coordinates, normal, texture);
}

void Face::setPoint(int position, const Vector &coordinates, const Vector &normal, const Vector &texture)
{
    if ((position < 0) || (position >= count())) {
        qDebug() << "Trying to modify an inexistant point at position" << position;
        return;
    }
    m_coordinates[position] = coordinates;
    m_normals[position] = normal;
    m_textures[position] = texture;
}

void Face::deletePoint(int position)
{
    if ( (position < 0) ||
         (position >= count()) ||
         (count() == 0) ) {
        return;
    }
    m_coordinates.removeAt(position);
    m_normals.removeAt(position);
    m_textures.removeAt(position);
}

const VectorList Face::getCoordinates() const
{
    return m_coordinates;
}

const VectorList Face::getNormals() const
{
    return m_normals;
}

const VectorList Face::getTextures() const
{
    return m_textures;
}

Vector Face::getCoordinate(int position) const
{
    if ((position < 0) || (position > count())) {
        qDebug() << "Trying to get an inexistant point at position" << position;
        return Vector();
    }

    return m_coordinates.value(position);
}

void Face::setCoordinate(int position, const Vector &coordinate)
{
    if ((position < 0) || (position >= count())) {
        qDebug() << "Trying to set the coordinates of an inexistant point at position" << position;
        return;
    }

    m_coordinates[position] = coordinate;
}

Vector Face::getNormal(int position) const
{
    if ((position < 0) || (position > count())) {
        qDebug() << "Trying to get an inexistant point at position" << position;
        return Vector();
    }

    return m_normals.value(position);
}

void Face::setNormal(int position, const Vector &normal)
{
    if ((position < 0) || (position >= count())) {
        qDebug() << "Trying to set the normal vector of an inexistant point at position" << position;
        return;
    }

    m_normals[position] = normal;
}

Vector Face::getTexture(int position) const
{
    if ((position < 0) || (position > count())) {
        qDebug() << "Trying to get an inexistant point at position" << position;
        return Vector();
    }

    return m_textures.value(position);
}

void Face::setTexture(int position, const Vector &texture)
{
    if ((position < 0) || (position >= count())) {
        qDebug() << "Trying to set the texture coordinates vector of an inexistant point at position" << position;
        return;
    }

    m_textures[position] = texture;
}

int Face::count() const
{
    return m_coordinates.count();
}

bool Face::isEmpty() const
{
    return m_coordinates.isEmpty();
}

void Face::setColor(const QColor &color)
{
    m_color = color;
}

QColor Face::getColor() const
{
    return m_color;
}

